﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
using SD.Common;
using Be.Windows.Forms;

namespace SocketClient
{
    /// <summary>
    /// 
    /// </summary>
    public partial class frmMain : Form
    {
        private const int ID_RECEIVEDBYTES = 0;
        private const int ID_SOCKETCLOSED = 1;
        private const int ID_SERIALPORT_RECEIVED = 3;
        private const int MAX_SENDITEM_NAME_LENGTH = 20;

        #region frmMain
        /// <summary>
        /// 
        /// </summary>
        public frmMain()
        {
            InitializeComponent();
            InitControls();
            RegisterSocketClientEvents();
            this.dataGridView1.AutoGenerateColumns = false;
        }
        #endregion //

        #region RegisterSocketClientEvents
        /// <summary>
        /// 
        /// </summary>
        private void RegisterSocketClientEvents()
        {
            this.SocketClient.ConnectedEvent += new EventHandler(SocketClient_ConnectedEvent);
            this.SocketClient.ClosedEvent += new EventHandler(SocketClient_ClosedEvent);
            this.SocketClient.ReceivedEvent += new EventHandler(SocketClient_ReceivedEvent);

            this.SerialPortManager.ReceivedEvent += new EventHandler(SerialPortManager_ReceivedEvent);
        }
        #endregion //RegisterSocketClientEvents

        #region SerialPortManager_ReceivedEvent
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SerialPortManager_ReceivedEvent(object sender, EventArgs e)
        {
            byte[] bs = this.SerialPortManager.ReceivedBytes;
            if (bs.Length > 0)
            {
                this.Post(ID_SERIALPORT_RECEIVED, bs);
            }
            return;
        }
        #endregion //SerialPortManager_ReceivedEvent

        #region Transmit
        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <param name="bs"></param>
        private void Transmit(object source, byte[] bs, LogItem logItem)
        {
            //dest = null;

            if (this.Transmitter.Enable &&
                this.Transmitter.CanTransmit())
            {
                IWrapper wrapper = GetWrapper();
                if (wrapper != null)
                {
                    bool isWrap = NeedWrap(source);
                    if (isWrap)
                    {
                        bs = wrapper.Wrap(bs);
                    }
                    else
                    {
                        bs = wrapper.Unwrap(bs);
                    }
                }

                ITransmit d = this.Transmitter.GetTo(source);
                if (d != null)
                {
                    d.Write(bs);

                    if (source is SocketClient)
                    {
                        logItem.StoragePoint.AddToEnd(this.CreateSerialPortStoragePoint());
                    }

                    if (source is SerialPortManager)
                    {
                        logItem.StoragePoint.AddToEnd(this.CreateRemoteStoragePoint());
                    }

                }
            }
        }
        #endregion //Transmit

        #region GetWrapper
        /// <summary>
        /// 
        /// </summary>
        private IWrapper GetWrapper()
        {
            return App.Default.WrapperManager.GetWrapper();
        }
        #endregion //GetWrapper

        #region NeedWrap
        /// <summary>
        /// 
        /// </summary>
        /// <param name="transmitSource"></param>
        /// <returns></returns>
        private bool NeedWrap(object transmitSource)
        {
            if (transmitSource is SerialPortManager)
            {
                return true;
            }

            if (transmitSource is SocketClient)
            {
                return false;
            }

            string msg = string.Format(
                "cannot determine wrap or unwrap by: '{0}'",
                transmitSource);
            throw new ArgumentException(msg);
        }
        #endregion //NeedWrap

        #region SocketClient_ReceivedEvent
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SocketClient_ReceivedEvent(object sender, EventArgs e)
        {
            byte[] bs = this.SocketClient.ReceivedBytes;
            this.Post(ID_RECEIVEDBYTES, bs);
        }
        #endregion //SocketClient_ReceivedEvent

        #region SocketClient_ClosedEvent
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SocketClient_ClosedEvent(object sender, EventArgs e)
        {
            this.OnSyncSocketClosed();
        }
        #endregion //SocketClient_ClosedEvent

        #region SocketClient_ConnectedEvent
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SocketClient_ConnectedEvent(object sender, EventArgs e)
        {
            this.SetConnectState();
        }
        #endregion //SocketClient_ConnectedEvent

        #region Transmitter
        /// <summary>
        /// 
        /// </summary>
        private Transmitter Transmitter
        {
            get { return App.Default.Transmitter; }
        }
        #endregion //Transmitter

        #region Config
        private Config Config
        {
            get { return App.Default.Config; }
        }
        #endregion //Config

        #region InitControls
        /// <summary>
        /// 
        /// </summary>
        private void InitControls()
        {
            this.MinimumSize = new Size(800, 600);

            this.tssTransmitter.Text = string.Empty;
            this.tssSocket.Text = string.Empty;

            // serial port
            //
            RefreshSerialPortState();


            // reply
            //
            RefreshReplyState();

            // transmit
            //
            RefreshTransmitState();

            RefreshSocketState();

            // listview
            //
            for (int i = 0; i < this.dataGridView1.Columns.Count; i++)
            {
                this.dataGridView1.Columns[i].Width = this.ColumnWidths[i];
            }

            //
            int[] tssWidths = new int[] { 350, 250, 120, 120 };
            ToolStripLabel[] tsls = new ToolStripLabel[] { tssSocket, tssSerialPort, tssTransmitter, tssReply };
            for (int i = 0; i < tssWidths.Length; i++)
            {
                tsls[i].Width = tssWidths[i];
            }


            this.WindowState = Config.FormWindowState;
            this.Size = Config.FormSize;
            this.Location = Config.Location;

            //
            //
            if (this.Config.LogDataMode == DataMode.Ascii)
            {
                this.mnuAscii.Checked = true;
                this.mnuHex.Checked = false;
            }
            else
            {
                this.mnuAscii.Checked = false;
                this.mnuHex.Checked = true;
            }

            RefreshLogDataGridView();

            tsbHex.Checked = Config.LogDataMode == DataMode.Hex;
            tsbAscii.Checked = Config.LogDataMode == DataMode.Ascii;

            SetDisconnectState();

            // 
            //
            CreateContextMenu();

            this.toolStrip1.Visible = Config.ToolBarVisible;
            this.statusStrip1.Visible = Config.StatusBarVisible;

            this.tsbShowRow.Checked = Config.HexBoxLineVisible;
            this.tsbShowCol.Checked = Config.HexBoxColumnVisible;
            //
            //
            InitHexControl();
            CreateDataGridViewContextMenu();
        }
        #endregion //InitControls

        #region CreateDataGridViewContextMenu
        private void CreateDataGridViewContextMenu()
        {
            this.dgvContextMenu.Items.Clear();
            this.dgvContextMenu.Items.Add(
                Strings.Copy,
                null,
                (s, e) =>
                {
                    if (this.dataGridView1.CurrentCell != null)
                    {
                        string cellValue = this.dataGridView1.CurrentCell.FormattedValue.ToString();
                        if (cellValue.Length > 0)
                        {
                            Clipboard.SetText(cellValue);
                        }
                    }
                }
                );

            this.dgvContextMenu.Items.Add(
                Strings.ClearLog,
                null,
                (s, e) =>
                {
                    ClearLog();
                }
                );
        }
        #endregion //CreateDataGridViewContextMenu

        #region InitHexControl
        private void InitHexControl()
        {
            this.hexSend.ColumnInfoVisible = this.Config.HexBoxColumnVisible;
            this.hexSend.LineInfoVisible = this.Config.HexBoxLineVisible;
            this.hexSend.StringViewVisible = true;
            this.hexSend.UseFixedBytesPerLine = true;
            this.hexSend.BytesPerLine = 16;
            this.hexSend.VScrollBarVisible = true;

            this.hexSend.ByteProvider = new Be.Windows.Forms.DynamicByteProvider(new byte[0]);
        }
        #endregion //InitHexControl

        #region CreateContextMenu
        /// <summary>
        /// 
        /// </summary>
        private void CreateContextMenu()
        {
            this.contextMenuStrip1.Items.Clear();

            ToolStripItem m = null;

            m = this.contextMenuStrip1.Items.Add(Strings.SendDataSave);
            m.Click += new EventHandler(SendAdd_Click);

            m = this.contextMenuStrip1.Items.Add(Strings.SendDataManage);
            m.Click += new EventHandler(SendManage_Click);

            if (this.SendCollection.Count > 0)
            {
                m = new ToolStripSeparator();
                this.contextMenuStrip1.Items.Add(m);

                for (int i = 0; i < this.SendCollection.Count; i++)
                {
                    SendItem si = this.SendCollection[i];
                    this.AddSendItemToContextMenu(si, i + 1);
                }
            }
        }
        #endregion //CreateContextMenu

        #region SendManage_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SendManage_Click(object sender, EventArgs e)
        {
            frmSendDataManager f = new frmSendDataManager();
            if (f.ShowDialog() == DialogResult.OK)
            {
                SendItem selectedItem = f.SelectedSendItem;
                if (selectedItem != null)
                {
                    SetSendBytes(selectedItem.Bytes);
                }
            }

            CreateContextMenu();
        }
        #endregion //SendManage_Click

        #region SendAdd_Click
        void SendAdd_Click(object sender, EventArgs e)
        {
            byte[] bs;
            if (this.GetSendBytes(out bs))
            {
                SendItem item = new SendItem();

                item.Name = CreateSendItemName(bs);
                item.Bytes = bs;

                frmSendData f = new frmSendData(item, false);
                if (f.ShowDialog() == DialogResult.OK)
                {
                    this.SendCollection.Add(item);
                    CreateContextMenu();
                }
            }
        }
        #endregion //SendAdd_Click

        #region CreateSendItemName
        /// <summary>
        /// 
        /// </summary>
        /// <param name="bs"></param>
        /// <returns></returns>
        private static string CreateSendItemName(byte[] bs)
        {
            var r = HexStringConverter.Default.ConvertToObject(bs).ToString();
            if (r.Length > MAX_SENDITEM_NAME_LENGTH)
            {
                return r.Substring(0, MAX_SENDITEM_NAME_LENGTH - 3) + "...";
            }
            else
            {
                return r;
            }
        }
        #endregion //CreateSendItemName

        #region AddSendItemToContextMenu
        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        private void AddSendItemToContextMenu(SendItem item, int no)
        {
            string s = string.Format(
                "{0}: {1}",
                GetNoMenuText(no),
                item.Name);


            ToolStripMenuItem menuitem = new ToolStripMenuItem(s);
            menuitem.Tag = item;
            menuitem.Click += new EventHandler(menuitem_Click);

            this.contextMenuStrip1.Items.Add(menuitem);
        }
        #endregion //AddSendItemToContextMenu

        #region GetNoMenuText
        /// <summary>
        /// 
        /// </summary>
        /// <param name="no"></param>
        /// <returns></returns>
        private string GetNoMenuText(int no)
        {
            if (no < 10)
            {
                return "0&" + no.ToString();
            }
            else
            {
                return no.ToString();
            }
        }
        #endregion //GetNoMenuText

        #region menuitem_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void menuitem_Click(object sender, EventArgs e)
        {
            ToolStripItem item = sender as ToolStripItem;
            SendItem senditem = (SendItem)item.Tag;
            SetSendBytes(senditem.Bytes);
        }
        #endregion //menuitem_Click

        #region SendCollection
        /// <summary>
        /// 
        /// </summary>
        private SendCollection SendCollection
        {
            get
            {
                return App.Default.Config.SendCollection;
            }
        }
        #endregion //SendCollection

        #region ColumnWidths
        /// <summary>
        /// 
        /// </summary>
        private int[] ColumnWidths
        {
            get
            {
                int minWidth = 30;

                _columnWidths = Config.ListViewColumnWidths;
                if (_columnWidths.Length != this.dataGridView1.Columns.Count)
                {
                    _columnWidths = new int[this.dataGridView1.Columns.Count];
                }

                for (int i = 0; i < _columnWidths.Length; i++)
                {
                    if (_columnWidths[i] < minWidth)
                    {
                        _columnWidths[i] = minWidth;
                    }
                }
                return _columnWidths;
            }
        } private int[] _columnWidths;
        #endregion //ColumnWidths

        #region RefreshSocketState
        /// <summary>
        /// 
        /// </summary>
        private void RefreshSocketState()
        {
            string s = string.Empty;
            if (this.SocketClient.IsConnected)
            {
                s = string.Format(
                    Strings.ConnectdFromTo,
                    this.SocketClient.IsUseUdp() ? Strings.UDP : Strings.TCP,
                    this.SocketClient.LocalEndPoint,
                    this.SocketClient.RemoteEndPoint
                    );
            }
            else
            {
                s = Strings.NotConnectdState;
            }
            this.tssSocket.Text = s;
            this.tssSocket.ForeColor = this.SocketClient.IsConnected ? Color.Black : Color.Gray;
        }
        #endregion //RefreshSocketState

        #region RefreshTransmitState
        private void RefreshTransmitState()
        {
            this.mnuEnableTransmit.Checked = this.Transmitter.Enable; ;

            string s = string.Format(
                Strings.TransmitState,
                this.Transmitter.Enable ? Strings.Enabled : Strings.Disabled
                );
            this.tssTransmitter.Text = s;

            this.tssTransmitter.ForeColor = this.Transmitter.Enable ? Color.Black : Color.Gray;
        }
        #endregion //RefreshTransmitState

        #region RefreshReplyState
        private void RefreshReplyState()
        {
            this.mnuEnableReply.Checked = this.ReplyCollection.Enabled;
            string s = string.Format(
                Strings.ReplyState,
                this.ReplyCollection.Enabled ? Strings.Enabled : Strings.Disabled
                );
            this.tssReply.Text = s;
            this.tssReply.ForeColor = this.ReplyCollection.Enabled ? Color.Black : Color.Gray;
        }
        #endregion //RefreshReplyState

        #region RefreshSerialPortState
        /// <summary>
        /// 
        /// </summary>
        private void RefreshSerialPortState()
        {
            this.mnuOpenSerialPort.Enabled = !this.SerialPortManager.IsOpen;
            this.mnuCloseSerialPort.Enabled = this.SerialPortManager.IsOpen;
            this.mnuSerialPortSetting.Enabled = !this.SerialPortManager.IsOpen;

            this.tssSerialPort.Text = string.Format(
                "{0} {1}",
                this.SerialPortManager.SerialPortSettings,
                this.SerialPortManager.IsOpen ? Strings.Opened : Strings.Closed);

            this.tssSerialPort.ForeColor = this.SerialPortManager.IsOpen ? Color.Black : Color.Gray;
        }
        #endregion //RefreshSerialPortState

        #region SocketClient
        private SocketClient SocketClient
        {
            get
            {
                return App.Default.SocketClient;
            }
        }
        #endregion //SocketClient

        #region SerialPortManager
        private SerialPortManager SerialPortManager
        {
            get
            {
                return App.Default.SerialPortManager;
            }
        }
        #endregion //

        #region Disconnect
        /// <summary>
        /// 
        /// </summary>
        private void Disconnect()
        {
            this.SocketClient.Close();
            SetDisconnectState();
        }
        #endregion //Disconnect

        #region OnSocketClosed
        /// <summary>
        /// 
        /// </summary>
        private void OnSocketClosed()
        {
            this.SetDisconnectState();
        }
        #endregion //OnSocketClosed

        #region SetConnectState
        /// <summary>
        /// 
        /// </summary>
        private void SetConnectState()
        {
            //this.grpSend.Enabled = true;
            this.tsbCreateConnection.Enabled = false;
            this.tsbLastConnection.Enabled = false;
            this.mnuCreateConnection.Enabled = false;
            this.mnuLastConnection.Enabled = false;
            this.tsbDisconnection.Enabled = true;
            this.mnuSend.Enabled = true;
            this.tsbSend.Enabled = true;

            if (Config.AutoClearLogWhenConnectionCreated)
            {
                ClearLog();
            }
            RefreshSocketState();
        }
        #endregion //SetConnectState

        #region SetDisConnectState
        /// <summary>
        /// 
        /// </summary>
        private void SetDisconnectState()
        {
            //this.grpSend.Enabled = false;
            this.tsbCreateConnection.Enabled = true;
            this.tsbLastConnection.Enabled = true;
            this.mnuCreateConnection.Enabled = true;
            this.mnuLastConnection.Enabled = true;
            this.tsbDisconnection.Enabled = false;
            this.mnuSend.Enabled = false;
            this.tsbSend.Enabled = false;
            RefreshSocketState();
        }
        #endregion //SetDisConnectState

        #region btnSend_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSend_Click(object sender, EventArgs e)
        {
            Send();
        }

        private void Send()
        {

            if (!this.SocketClient.IsConnected)
            {
                NUnit.UiKit.UserMessage.DisplayFailure(Strings.NotConnectdState);
                return;
            }

            byte[] buffer;
            bool success = GetSendBytes(out buffer);

            if (!success)
                return;

            try
            {
                this.SocketClient.Send(buffer);
            }
            catch (SocketException socketEx)
            {
                NUnit.UiKit.UserMessage.DisplayFailure(socketEx.Message);
                return;
            }

            StoragePoint sp = this.CreateLocalStoragePoint();
            sp.Out = this.CreateRemoteStoragePoint();

            LogItem log = new LogItem(DateTime.Now, buffer, sp);
            this.AddLog(log);
        }
        #endregion //btnSend_Click

        #region GetSendBytes
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private bool GetSendBytes(out byte[] outBS)
        {
            outBS = null;
            var p = this.hexSend.ByteProvider as DynamicByteProvider;
            if (p.Bytes.Count > 0)
            {
                outBS = p.Bytes.ToArray();
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion //GetSendBytes

        #region SetSendBytes
        /// <summary>
        /// 
        /// </summary>
        /// <param name="bytes"></param>
        private void SetSendBytes(byte[] bytes)
        {
            var p = this.hexSend.ByteProvider;
            p.DeleteBytes(0, p.Length);
            p.InsertBytes(0, bytes);
            this.hexSend.Refresh();
        }
        #endregion //SetSendBytes

        #region btnClearReceived_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClearReceived_Click(object sender, EventArgs e)
        {
        }
        #endregion //btnClearReceived_Click

        #region ClearLog
        private void ClearLog()
        {
            this.LogManager.Items.Clear();
            this.dataGridView1.Rows.Clear();
        }
        #endregion //ClearLog

        #region LogManager
        /// <summary>
        /// 
        /// </summary>
        public LogManager LogManager
        {
            get { return App.Default.LogManager; }
        }
        #endregion //LogManager

        #region grpReceived_Enter
        private void grpReceived_Enter(object sender, EventArgs e)
        {

        }
        #endregion //grpReceived_Enter

        #region btnSendHistory_Click
        private void btnSendHistory_Click(object sender, EventArgs e)
        {
            Point pt = Form.MousePosition;
            this.contextMenuStrip1.Show(pt);
        }
        #endregion //btnSendHistory_Click

        #region ReplyCollection
        /// <summary>
        /// 
        /// </summary>
        private ReplyList ReplyCollection
        {
            get { return App.Default.ReplyManager.ReplyCollection; }
        }
        #endregion //ReplyCollection

        #region AddLog
        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        private void AddLog(LogItem item)
        {
            this.LogManager.Items.Add(item);

            AddLogItemToDataGridView(item);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        private void AddLogItemToDataGridView(LogItem item)
        {
            string datas = string.Empty;
            if (this.Config.LogDataMode == DataMode.Ascii)
            {
                datas = Encoding.ASCII.GetString(item.Bytes);
            }
            if (this.Config.LogDataMode == DataMode.Hex)
            {
                datas = (string)HexStringConverter.Default.ConvertToObject(item.Bytes);
            }

            List<object> rowList = new List<object>();
            rowList.Add(item.DT);
            foreach (object obj in item.StoragePoint.ToArray())
            {
                rowList.Add(obj);
            }
            rowList.Add(item.Bytes.Length);
            rowList.Add(datas);
            int idx = this.dataGridView1.Rows.Add(//item.ToArray());
                rowList.ToArray());
            DataGridViewRow dgvRow = this.dataGridView1.Rows[idx];

            dgvRow.DefaultCellStyle = GetCellStyle(item.StoragePoint.EnsureDirection());
            this.dataGridView1.CurrentCell = this.dataGridView1.Rows[idx].Cells[0];
        }
        #endregion //AddLog

        #region GetCellStyle
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dd"></param>
        /// <returns></returns>
        private DataGridViewCellStyle GetCellStyle(DataDirection dd)
        {
            DataGridViewCellStyle obj = _cellStyleHashTable[dd] as DataGridViewCellStyle;
            if (obj == null)
            {
                DataGridViewCellStyle style = new DataGridViewCellStyle(this.dataGridView1.DefaultCellStyle);
                style.BackColor = dd.BackColor;
                _cellStyleHashTable[dd] = style;
                return style;
            }
            else
            {
                return obj;
            }
        } private Hashtable _cellStyleHashTable = new Hashtable();
        #endregion //GetCellStyle

        #region SyncContext
        /// <summary>
        /// 
        /// </summary>
        public SynchronizationContext SyncContext
        {
            get { return App.Default.SyncContext; }
        }
        #endregion //SyncContext

        #region Post
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="state"></param>
        public void Post(int id, object state)
        {
            SendOrPostCallback d = GetSendOrPostCallback();
            PostStateObject stateObj = new PostStateObject(id, state);
            this.SyncContext.Post(d, stateObj);
        }
        #endregion //Post

        #region GetSendOrPostCallback
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private SendOrPostCallback GetSendOrPostCallback()
        {
            if (_sendOrPostCallback == null)
            {
                _sendOrPostCallback = new SendOrPostCallback(SendOrPostCallbackTarget);
            }
            return _sendOrPostCallback;
        } private SendOrPostCallback _sendOrPostCallback;
        #endregion //GetSendOrPostCallback

        #region GetRemoteString
        private string GetRemoteString()
        {
            return App.Default.SocketClient.RemoteEndPoint.ToString();
        }

        private StoragePoint CreateRemoteStoragePoint()
        {
            return App.Default.SocketClient.CreateRemoteStoragePoint();
        }
        #endregion //GetRemoteString

        #region CreateLocalStoragePoint
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private StoragePoint CreateLocalStoragePoint()
        {
            return App.Default.SocketClient.CreateLocalStoragePoint();
        }
        #endregion //CreateLocalStoragePoint

        #region GetSerialPortName
        private string GetSerialPortName()
        {
            return App.Default.SerialPortManager.SerialPortSettings.PortName;
        }
        #endregion //GetSerialPortName

        #region CreateSerialPortStoragePoint
        private StoragePoint CreateSerialPortStoragePoint()
        {
            return new StoragePoint(StoragePointType.Com,
                App.Default.SerialPortManager.SerialPortSettings.PortName);
        }
        #endregion //CreateSerialPortStoragePoint

        #region SendOrPostCallbackTarget
        /// <summary>
        /// 
        /// </summary>
        /// <param name="state"></param>
        private void SendOrPostCallbackTarget(object state)
        {
            PostStateObject stateObj = state as PostStateObject;
            switch (stateObj.ID)
            {
                case ID_RECEIVEDBYTES:
                    byte[] bs = stateObj.State as byte[];
                    StoragePoint sp = CreateRemoteStoragePoint();
                    sp.Out = CreateLocalStoragePoint();
                    LogItem logItem = new LogItem(DateTime.Now, bs, sp);

                    Transmit(this.SocketClient, bs, logItem);

                    this.AddLog(logItem);

                    if (this.ReplyCollection.Enabled)
                    {
                        byte[] bsr = this.ReplyCollection.GetSendBytes(bs);
                        if (bsr != null)
                        {
                            this.SocketClient.Send(bsr);
                            StoragePoint spr = CreateLocalStoragePoint();
                            spr.Out = CreateRemoteStoragePoint();

                            LogItem logItemr = new LogItem(DateTime.Now, bsr, spr);
                            this.AddLog(logItemr);
                        }
                    }

                    break;

                case ID_SOCKETCLOSED:
                    this.OnSocketClosed();
                    break;

                case ID_SERIALPORT_RECEIVED:
                    byte[] bs2 = (byte[])stateObj.State;

                    StoragePoint spc = CreateSerialPortStoragePoint();
                    spc.Out = CreateLocalStoragePoint();

                    LogItem logItemC = new LogItem(DateTime.Now, bs2, spc);
                    Transmit(this.SerialPortManager, bs2, logItemC);

                    this.AddLog(logItemC);
                    break;

            }
        }
        #endregion //SendOrPostCallbackTarget

        #region OnSyncSocketClosed
        /// <summary>
        /// 
        /// </summary>
        public void OnSyncSocketClosed()
        {
            this.Post(ID_SOCKETCLOSED, null);
        }
        #endregion //OnSyncSocketClosed

        #region tsbSerialPort_Click
        private void tsbSerialPort_Click(object sender, EventArgs e)
        {
        }
        #endregion //tsbSerialPort_Click

        #region mnuEnableTransmit_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuEnableTransmit_Click(object sender, EventArgs e)
        {
            this.Transmitter.Enable = !this.Transmitter.Enable;
            this.RefreshTransmitState();
        }
        #endregion //mnuEnableTransmit_Click

        #region mnuSerialPortSetting_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuSerialPortSetting_Click(object sender, EventArgs e)
        {
            frmSerialPort f = new frmSerialPort();
            f.SerialPortSettings = this.SerialPortManager.SerialPortSettings;

            DialogResult dr = f.ShowDialog(this);
            if (dr == DialogResult.OK)
            {
                RefreshSerialPortState();
                //RefreshStatus();
            }
        }
        #endregion //mnuSerialPortSetting_Click

        #region mnuEnableReply_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuEnableReply_Click(object sender, EventArgs e)
        {
            this.ReplyCollection.Enabled = !this.ReplyCollection.Enabled;
            Config.EnabledReply = this.ReplyCollection.Enabled;
            RefreshReplyState();

        }
        #endregion //mnuEnableReply_Click

        #region mnuReplySetting_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuReplySetting_Click(object sender, EventArgs e)
        {
            frmReplyManager2 f = new frmReplyManager2(this.ReplyCollection);
            f.ShowDialog();
        }
        #endregion //mnuReplySetting_Click

        #region mnuOpenSerialPort_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuOpenSerialPort_Click(object sender, EventArgs e)
        {
            if (!this.SerialPortManager.IsOpen)
            {
                try
                {
                    this.SerialPortManager.Open();
                }
                catch (Exception ex)
                {
                    NUnit.UiKit.UserMessage.DisplayFailure(ex.Message);
                    return;
                }

                RefreshSerialPortState();
            }
        }

        #endregion //mnuOpenSerialPort_Click

        #region mnuCloseSerialPort_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuCloseSerialPort_Click(object sender, EventArgs e)
        {
            if (this.SerialPortManager.IsOpen)
            {
                this.SerialPortManager.Close();
                RefreshSerialPortState();
            }
        }
        #endregion //mnuCloseSerialPort_Click

        #region frmMain_FormClosed
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            //
            //
            int[] columnWidths = new int[this.dataGridView1.Columns.Count];
            for (int i = 0; i < this.dataGridView1.Columns.Count; i++)
            {
                columnWidths[i] = this.dataGridView1.Columns[i].Width;
            }
            this.Config.ListViewColumnWidths = columnWidths;

            Config.FormWindowState = this.WindowState;

            if (this.WindowState == FormWindowState.Normal)
            {
                Config.FormSize = this.Size;
                Config.Location = this.Location;
            }

        }
        #endregion //frmMain_FormClosed

        #region RefreshLogDataGridView
        /// <summary>
        /// 
        /// </summary>
        private void RefreshLogDataGridView()
        {
            this.dataGridView1.Rows.Clear();
            string dataHeader = Strings.DataHex;
            if (this.Config.LogDataMode == DataMode.Ascii)
            {
                dataHeader = Strings.DataAscii;
            }

            this.dataGridView1.Columns["colDatas"].HeaderText = dataHeader;
            foreach (LogItem li in this.LogManager.Items)
            {
                this.AddLogItemToDataGridView(li);
            }
        }
        #endregion //RefreshLogDataGridView


        #region mnuExit_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        #endregion //mnuExit_Click

        #region mnuAbout_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuAbout_Click(object sender, EventArgs e)
        {
            string text = string.Format(
                "{0}\r\n{1}\r\n\r\n{2}",
                Application.ProductName,
                Application.ProductVersion,
                Strings.Mail);

            MessageBox.Show(this, text, 
                Strings.About, 
                MessageBoxButtons.OK, 
                MessageBoxIcon.Information);
        }
        #endregion //mnuAbout_Click

        #region mnuSaveLog_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuSaveLog_Click(object sender, EventArgs e)
        {
            SaveLog();
        }
        #endregion //mnuSaveLog_Click

        #region SaveLog
        private void SaveLog()
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";

            if (sfd.ShowDialog() == DialogResult.OK)
            {
                string path = sfd.FileName;
                LogSaver saver = new LogSaver(this.LogManager);
                try
                {
                    saver.Save(path);
                }
                catch (Exception ex)
                {
                    NUnit.UiKit.UserMessage.DisplayFailure(ex.Message);
                }
            }
        }
        #endregion //SaveLog

        #region mnuWrapperManager_Click
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuWrapperManager_Click(object sender, EventArgs e)
        {
            frmWrapperManager f = new frmWrapperManager();
            f.ShowDialog();
        }
        #endregion //mnuWrapperManager_Click

        #region tssReply_Click
        private void tssReply_Click(object sender, EventArgs e)
        {
            mnuEnableReply_Click(null, null);
        }
        #endregion //tssReply_Click

        #region tssTransmitter_Click
        private void tssTransmitter_Click(object sender, EventArgs e)
        {
            mnuEnableTransmit_Click(null, null);
        }
        #endregion //tssTransmitter_Click

        #region frmMain_Load
        private void frmMain_Load(object sender, EventArgs e)
        {

        }
        #endregion //frmMain_Load

        #region tssSerialPort_Click
        private void tssSerialPort_Click(object sender, EventArgs e)
        {
            mnuOpenSerialPort_Click(null, null);
        }
        #endregion //tssSerialPort_Click

        #region tssSocket_Click
        private void tssSocket_Click(object sender, EventArgs e)
        {
            //btnConnect_Click(null, null);
        }
        #endregion //tssSocket_Click

        #region IsCell
        private bool IsCell(int rowIndex, int colIndex)
        {
            return rowIndex >= 0 && colIndex >= 0;
        }
        #endregion //IsCell

        #region dataGridView1_CellMouseUp
        private void dataGridView1_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                if (IsCell(e.RowIndex, e.ColumnIndex))
                {
                    this.dgvContextMenu.Show(MousePosition);
                }
            }
        }

        #endregion //dataGridView1_CellMouseUp

        #region dataGridView1_CellMouseDown
        private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (IsCell(e.RowIndex, e.ColumnIndex))
            {
                this.dataGridView1.CurrentCell = this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];
            }
        }
        #endregion //dataGridView1_CellMouseDown

        #region mnuCreateConnection_Click
        private void mnuCreateConnection_Click(object sender, EventArgs e)
        {
            CreateNewConnection();
        }
        #endregion //mnuCreateConnection_Click

        #region CreateNewConnection
        private void CreateNewConnection()
        {
            var f = new frmCreateNewConnection().ShowDialog();
            if (f == System.Windows.Forms.DialogResult.OK)
            {
                SetConnectState();
            }
        }
        #endregion //CreateNewConnection

        #region mnuDisconnect_Click
        private void mnuDisconnect_Click(object sender, EventArgs e)
        {
            DisConnection();
        }
        #endregion //mnuDisconnect_Click

        #region DisConnection
        private void DisConnection()
        {
            if (this.SocketClient.IsConnected)
            {
                this.SocketClient.Close();
                SetDisconnectState();
            }
        }
        #endregion //DisConnection

        #region mnuConnect_DropDownOpening
        private void mnuConnect_DropDownOpening(object sender, EventArgs e)
        {
            this.mnuCreateConnection.Enabled = (!this.SocketClient.IsConnected);
            this.mnuDisconnect.Enabled = this.SocketClient.IsConnected;

        }
        #endregion //mnuConnect_DropDownOpening

        #region mnuAscii_Click
        private void mnuAscii_Click(object sender, EventArgs e)
        {
            SetLogDataViewAsciiMode();
        }
        #endregion //mnuAscii_Click

        #region SetLogDataViewAsciiMode
        private void SetLogDataViewAsciiMode()
        {
            if (this.Config.LogDataMode != DataMode.Ascii)
            {
                this.Config.LogDataMode = DataMode.Ascii;
                RefreshLogDataGridView();
                mnuAscii.Checked = true;
                tsbAscii.Checked = true;
                mnuHex.Checked = false;
                tsbHex.Checked = false;
            }
        }
        #endregion //SetLogDataViewAsciiMode

        #region mnuHex_Click
        private void mnuHex_Click(object sender, EventArgs e)
        {
            SetLogDataViewHexMode();
        }
        #endregion //mnuHex_Click

        #region SetLogDataViewHexMode
        private void SetLogDataViewHexMode()
        {
            if (this.Config.LogDataMode != DataMode.Hex)
            {
                this.Config.LogDataMode = DataMode.Hex;
                RefreshLogDataGridView();
                mnuHex.Checked = true;
                tsbHex.Checked = true;
                mnuAscii.Checked = false;
                tsbAscii.Checked = false;
            }
        }
        #endregion //SetLogDataViewHexMode

        #region mnuClearLog_Click
        private void mnuClearLog_Click(object sender, EventArgs e)
        {
            ClearLog();
        }
        #endregion //mnuClearLog_Click

        #region tsbHex_Click
        private void tsbHex_Click(object sender, EventArgs e)
        {
            SetLogDataViewHexMode();
        }
        #endregion //tsbHex_Click

        #region tsbAscii_Click
        private void tsbAscii_Click(object sender, EventArgs e)
        {
            SetLogDataViewAsciiMode();
        }
        #endregion //tsbAscii_Click

        #region tsbClear_Click
        private void tsbClear_Click(object sender, EventArgs e)
        {
            ClearLog();
        }
        #endregion //tsbClear_Click

        #region tsbCreateConnection_Click
        private void tsbCreateConnection_Click(object sender, EventArgs e)
        {
            CreateNewConnection();
        }
        #endregion //tsbCreateConnection_Click

        #region tsbDisconnection_Click
        private void tsbDisconnection_Click(object sender, EventArgs e)
        {
            Disconnect();
        }
        #endregion //tsbDisconnection_Click

        #region tsbLastConnection_Click
        private void tsbLastConnection_Click(object sender, EventArgs e)
        {
            if (CreateConnectWithLastConfig())
            {
                SetConnectState();
            }
        }
        #endregion //tsbLastConnection_Click

        #region CreateConnectWithLastConfig
        private bool CreateConnectWithLastConfig()
        {
            if (!Config.HasLastConfigs())
            {
                CreateNewConnection();
                return false;
            }

            try
            {
                if (Config.IsUseLocalPort)
                {
                    this.SocketClient.Connect(
                        IPAddress.Parse(this.Config.LastIPAddress),
                        this.Config.LastPort,
                        Config.LocalPort,
                        this.Config.LastProtocolType);
                }
                else
                {
                    this.SocketClient.Connect(
                        IPAddress.Parse(this.Config.LastIPAddress),
                        this.Config.LastPort,
                        this.Config.LastProtocolType);
                }
            }
            catch (SocketException socketEx)
            {
                NUnit.UiKit.UserMessage.DisplayFailure(socketEx.Message);
                return false;
            }
            this.SocketClient.BeginReceive();
            return true;
        }
        #endregion //CreateConnectWithLastConfig

        #region mnuLastConnection_Click
        private void mnuLastConnection_Click(object sender, EventArgs e)
        {
            if (CreateConnectWithLastConfig())
            {
                SetConnectState();
            }
        }
        #endregion //mnuLastConnection_Click

        #region mnuToolBar_Click
        private void mnuToolBar_Click(object sender, EventArgs e)
        {
            this.toolStrip1.Visible = !this.toolStrip1.Visible;
            this.Config.ToolBarVisible = this.toolStrip1.Visible;
            this.mnuToolBar.Checked = this.toolStrip1.Visible;
        }
        #endregion //mnuToolBar_Click

        #region mnuStatusBar_Click
        private void mnuStatusBar_Click(object sender, EventArgs e)
        {
            this.statusStrip1.Visible = !this.statusStrip1.Visible;
            this.Config.StatusBarVisible = this.statusStrip1.Visible;
            this.mnuStatusBar.Checked = this.statusStrip1.Visible;
        }
        #endregion //mnuStatusBar_Click

        #region mnuView_DropDownOpening
        private void mnuView_DropDownOpening(object sender, EventArgs e)
        {
            this.mnuToolBar.Checked = this.toolStrip1.Visible;
            this.mnuStatusBar.Checked = this.statusStrip1.Visible;
        }
        #endregion //mnuView_DropDownOpening

        #region mnuSend_Click
        private void mnuSend_Click(object sender, EventArgs e)
        {
            if (SocketClient.IsConnected)
            {
                btnSend_Click(null, null);
            }
        }
        #endregion //mnuSend_Click

        #region tsbSave_Click
        private void tsbSave_Click(object sender, EventArgs e)
        {
            SaveLog();
        }
        #endregion //tsbSave_Click

        #region tsbShowRow_Click
        private void tsbShowRow_Click(object sender, EventArgs e)
        {
            this.tsbShowRow.Checked = !this.tsbShowRow.Checked;
            this.hexSend.LineInfoVisible = this.tsbShowRow.Checked;
            this.Config.HexBoxLineVisible = this.hexSend.LineInfoVisible;
        }
        #endregion //tsbShowRow_Click

        #region tsbShowCol_Click
        private void tsbShowCol_Click(object sender, EventArgs e)
        {
            this.tsbShowCol.Checked = !this.tsbShowCol.Checked;
            this.hexSend.ColumnInfoVisible = this.tsbShowCol.Checked;
            this.Config.HexBoxColumnVisible = this.hexSend.ColumnInfoVisible;
        }
        #endregion //tsbShowCol_Click

        #region tsbSendHistory_Click
        private void tsbSendHistory_Click(object sender, EventArgs e)
        {
            Point pt = Form.MousePosition;
            this.contextMenuStrip1.Show(pt);
        }
        #endregion //tsbSendHistory_Click

        #region tsbSend_Click
        private void tsbSend_Click(object sender, EventArgs e)
        {
            Send();
        }
        #endregion //tsbSend_Click

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbClearSend_Click(object sender, EventArgs e)
        {
            var length = this.hexSend.ByteProvider.Length;
            this.hexSend.ByteProvider.DeleteBytes(0, length);
            this.hexSend.ByteProvider.ApplyChanges();
            this.hexSend.Refresh();
        }
    }
}
